module MapTiles
  Grass = 0
  Earth = 1
end

class Map
  attr_reader :width, :height
  TILE_WIDTH = 5
  TILE_HEIGHT = 5
  TILE_DRAWN_WIDTH = 60
  TILE_DRAWN_HEIGHT = 60
  TILE_DRAWN_OVERLAP = 5
  def initialize(window, width, height)
    @draw_actual = false
    @window = window
    @craters = []
    @tileset = Image.load_tiles(window, "media/tileset.png", TILE_DRAWN_WIDTH, TILE_DRAWN_HEIGHT, true)
    @sky = Images["media/space.png"]
    @crater_image = Image.new(window, "media/crater.png", true)
    @pixel_width, @pixel_height = width, height
    @width, @height = width/TILE_WIDTH, height/TILE_HEIGHT
    
    create_actual_map
    create_drawn_map
  end
  
  def create_actual_map
    prev_height = 0
    next_height = @height / 3
    @heights = [next_height]
    @actual_map = Array.new(@width) do |x| #increments of TILE_WIDTH
      if x % (tile_distance/TILE_WIDTH) == 0
        prev_height = next_height
        next_height += rand(tile_distance / TILE_HEIGHT * 2) - tile_distance / TILE_HEIGHT
        next_height = @height/2 if next_height > @height/2
        next_height = @height/5 if next_height < @height/6
        @heights << next_height
      end
      intermediate_height = next_height + (prev_height - next_height) * (tile_distance - ((x * TILE_WIDTH) % tile_distance)) / tile_distance.to_f
      #DebugOut.out "intermediate_height#{intermediate_height} prev_height#{prev_height} next_height#{next_height}"
      a = Array.new(@height) do |y|
        if y > intermediate_height
          nil
        else
          1
        end
      end
      a
    end
  end
  
  def create_drawn_map
    @drawn_map = Array.new(@heights.size - 1)
    (@heights.size - 1).times do |x|
      @drawn_map[x] = []
      ground_height = ([@heights[x] * TILE_HEIGHT, @heights[x+1] * TILE_HEIGHT].min - tile_distance)
      (@pixel_height / tile_distance).times do |y|
        if y * tile_distance < ground_height
          @drawn_map[x] << MapTiles::Earth
        elsif y == ground_height
          @drawn_map[x] << MapTiles::Grass
        else
          @drawn_map[x] << nil
        end
      end
    end
  end
  
  def [](x)
    x /= TILE_WIDTH
    ret = 0
    @actual_map[x].each_with_index do |t, y|
      ret = y if t != nil
    end
    ret = @pixel_height - TILE_HEIGHT * ret
  end
  
  def draw
    (@pixel_height / 480 + 1).times do |y|
      (@pixel_width / 640 + 1).times do |x|
        @sky.draw(x * 640, y * 480, ZOrder::Sky)
      end
    end
    if @draw_actual
      @height.times do |y|
        @width.times do |x|
          tile = @actual_map[x][y]
          if tile
            # Draw the tile with an offset (tile images have some overlap)
            #@tileset[tile].draw(x * TILE_WIDTH, @window.height - y * TILE_HEIGHT, 0, 0.2, 0.2)
            
            @window.draw_quad(x * TILE_WIDTH, @window.height - y * TILE_HEIGHT, 0xffffffff,
                              (x+1) * TILE_WIDTH, @window.height - y * TILE_HEIGHT, 0xffffffff,
                              x * TILE_WIDTH, @window.height - (y+1) * TILE_HEIGHT, 0xffffffff,
                              (x+1) * TILE_WIDTH, @window.height - (y+1) * TILE_HEIGHT, 0xffffffff, ZOrder::Map)
          end
        end
      end
    else
      @drawn_map.size.times do |x|
        top = true
        @drawn_map[x].size.times do |y|
          tile = @drawn_map[x][y]
          if tile
            # Draw the tile with an offset (tile images have some overlap)
            @tileset[tile].draw(x * tile_distance, @window.height - y * tile_distance, ZOrder::Map, 1, 1)
          elsif top
            @tileset[0].draw_as_quad(x * tile_distance - TILE_DRAWN_OVERLAP*1.5, @window.height - @heights[x] * TILE_HEIGHT - TILE_HEIGHT*2, 0xffffffff, # - TILE_HEIGHT*2 is a pragmatic adjustment
                                    (x+1) * tile_distance + TILE_DRAWN_OVERLAP*1.5, @window.height - @heights[x+1] * TILE_HEIGHT - TILE_HEIGHT*2, 0xffffffff, # - TILE_HEIGHT*2 is a pragmatic adjustment
                                    x * tile_distance - TILE_DRAWN_OVERLAP*1.5, @window.height - (y-1) * tile_distance + TILE_DRAWN_OVERLAP*2, 0xffffffff, 
                                    (x+1) * tile_distance + TILE_DRAWN_OVERLAP*1.5, @window.height - (y-1) * tile_distance + TILE_DRAWN_OVERLAP*2, 0xffffffff, ZOrder::Map)
            top = false
          end
        end
      end
      @craters.each do |c|
        @crater_image.draw(c[0] - c[2],@window.height - (c[1] + c[2]), ZOrder::MapEffects, c[2]*2.0 / 40, c[2]*2.0/40)
      end
    end
  end
  
  def tile_distance
    (TILE_DRAWN_WIDTH - TILE_DRAWN_OVERLAP * 2)
  end
  
  def toggle_display
    @draw_actual = !@draw_actual
  end
  
  def would_fit(x, y, width, height)
    @actual_map[(x - width/2)/TILE_WIDTH][(y-height/2)/TILE_HEIGHT] == nil and
      @actual_map[(x + width/2)/TILE_WIDTH][(y-height/2)/TILE_HEIGHT] == nil and
      @actual_map[(x - width/2)/TILE_WIDTH][(y+height/2)/TILE_HEIGHT] == nil and
      @actual_map[(x + width/2)/TILE_WIDTH][(y+height/2)/TILE_HEIGHT] == nil
  end
  
  def height_at_x(x)
    ret = 0
    @actual_map[x/TILE_WIDTH].each_with_index {|m, i| ret = i if m }
    ret
  end
  
  def lowest_height_at_x_above_y(x, y)
    ret = 0
    @actual_map[x/TILE_WIDTH][y/TILE_HEIGHT..$game.height/TILE_HEIGHT].each_with_index do |m, i| 
      if m == nil
        ret = i + y/TILE_HEIGHT - 1
        break
      end
    end
    #DebugOut.out "got #{@actual_map[x/TILE_WIDTH][$game.height/TILE_HEIGHT - 10] == nil}, height: #{ret}"
    raise if ret == 0
    ret * TILE_HEIGHT
  end
  
  def get_angle(x, y)
    #DebugOut.out x - TILE_WIDTH, lowest_height_at_x_above_y(x - TILE_WIDTH, y - 10)
    point1 = [x - TILE_WIDTH, lowest_height_at_x_above_y(x - TILE_WIDTH, y - 100)] #dubious
    point2 = [x + TILE_WIDTH, lowest_height_at_x_above_y(x + TILE_WIDTH, y - 100)] #dubious
    ret = angle(point1[0], -point1[1], point2[0], -point2[1])
    ret -= 360 if ret > 180
    ret
  end
  
  def add_crater(center_x, center_y, radius)
    (radius*2).times do |y|
      x1 = center_x - Math.sqrt(radius ** 2 - (radius - y) ** 2)
      x2 = center_x + Math.sqrt(radius ** 2 - (radius - y) ** 2)
      x1.to_i.upto(x2.to_i) do |new_x|
        @actual_map[new_x/TILE_WIDTH][(center_y + y - radius)/TILE_HEIGHT] = nil ###
      end
      #@actual_map[x2/TILE_WIDTH][(center_y + y - radius)/TILE_HEIGHT] = nil ###
      #draw_line(x1, @window.height - y + radius - center_y, color, x2, @window.height - y + radius - center_y, color, 10)
      #create_drawn_map
    end
    @craters << [center_x, center_y, radius]
  end
end